
local Entity = class("Entity")
local Types = import(".Types")
local ActNames = import("..models.ActNames")
Entity.idx_ = 1

Entity.ANIMATION_IDLE_TIME = 0.2 	-- idle animation frame time
Entity.ANIMATION_MOVE_TIME = 0.1	-- move animation frame time
-- Entity.ANIMATION_ATK_TIME  = 0.1 	-- attack animation frame time
-- Entity.ANIMATION_DEATH_TIME  = 0.1 	-- attack animation frame time

Entity.VIEW_TAG_CLOTH = 101

Entity.ANCHOR = cc.p(0.5, 0.5)

for k,v in pairs(Types) do
	Entity[k] = v
end


--require之后
--package.loaded[luafile] 会被赋值 如果要重新加载  则需要package.loaded[luafile]  = nil
--这表示加载后的 类的返回值实际已经是生存期全局了 用package.loaded[luafile]可以获得类的返回值
--下面的self已经不是Entity这个类了  是以Entity为元表重新创建出来的一个table
function Entity:ctor(args)  
	args = args or {}
	self.imageName_ = args.image
	self.id = 0
	self.idx_ = Entity.idx_
	Entity.idx_ = Entity.idx_ + 1
	self.type_ = args.type
	self.camera = args.camera
	
	cc.bind(self, "event")
	self:getView() -- create view

	self:bindStateMachine_(args.states)
end

function Entity:bindStateMachine_(states)
	local sm = cc.load("statemachine")

	local baseState = {
		events = {
			{name = "born",		from = "none",   		to = "idle" },
			{name = "kill",   	from = sm.WILDCARD,   	to = "death" }
		},

		callbacks = {
			onbeforeevent = handler(self, self.onBeforeEvent),
			onafterevent = handler(self, self.onAfterEvent),
			onenterstate = handler(self, self.onEnterState),
			onleavestate = handler(self, self.onLeaveState),
			onchangestate = handler(self, self.onChangeState)
		}
	}

	states = states or baseState
	states.callbacks = states.callbacks or {}
	states.callbacks.onbeforeevent = baseState.callbacks.onbeforeevent
	states.callbacks.onafterevent = baseState.callbacks.onafterevent
	states.callbacks.onenterstate = baseState.callbacks.onenterstate
	states.callbacks.onleavestate = baseState.callbacks.onleavestate
	states.callbacks.onchangestate = baseState.callbacks.onchangestate

	self.fsm_ = {}
	cc.bind(self.fsm_, "statemachine")

	self.fsm_:setupState(states)
	self:doEvent("born")
end

function Entity:onBeforeEvent(event)
	-- body
end

function Entity:onAfterEvent(event)
	printInfo("Entity:onAfterEvent state:" .. event.to)

	if "idle" == event.to then
		local actionName = ActNames[self.orientation + 8]
		self:play(actionName)
	elseif "death" == event.to then
		self:dispatchEvent({name = "death"})
		self:playDeath()
	end
end

function Entity:onEnterState(event)
end

function Entity:onLeaveState(event)
	-- body
end

function Entity:onChangeState(event)
	-- body
end

function Entity:doEvent(eventName)
	if self.fsm_:canDoEvent(eventName) then
		self.fsm_:doEvent(eventName)
	else
		printError("Entity can't do event:" .. eventName)
	end
end

function Entity:getView()
	if self.view_ then
		return self.view_
	end

	self.view_ = display.newNode()
	self.cloth = display.newSprite("1.png"):addTo(self.view_, Entity.VIEW_TAG_CLOTH):align(self.ANCHOR, 0, 0)
	return self.view_
end

function Entity:play(actionName, args)

	local animation = ManagerRes.getCharacterMapAction(self.imageName_, actionName)
    animation:setDelayPerUnit(self:getAnimationTime(actionName))
    local action = cc.Animate:create(animation)
    self.cloth:stopAllActions()
    if args and args.isOnce then
		args.isOnce = false  -- remove used params
		self.cloth:runAction(action)
	else
		self.cloth:runAction(cc.RepeatForever:create(action))
	end

end

function Entity:playDeath()
	self:setId(0) -- invalid id
	self:play("death",
		{
			removeSelf = true,
			onComplete = function()
				Game:removeEntity(self)
			end,
			isOnce = true
		})
end

function Entity:getAnimationTime(actionName)
	local pos = string.find(actionName, "_")
	local action = actionName
	if pos then
		action = string.sub(actionName, 1, pos - 1)
	end

	if "idle" == action then
		return self.ANIMATION_IDLE_TIME
	elseif "walk" == action then
		return self.ANIMATION_MOVE_TIME
	else
		return self.ANIMATION_IDLE_TIME
	end
end


function Entity:setMapPos(pos)
	self.view_:setPosition(ManagerMap:pos2px(pos))
end

function Entity:getMapPos()
	local posX, posY = self.view_:getPosition()
	return  ManagerMap:px2pos(cc.p(posX, posY))
end

return Entity
